#include "Debug.h"
#include "UVMapperCmd.h"
#include <maya/MGlobal.h>

UVMapper::UVMapper()
{  
}

UVMapper::~UVMapper()
{
}

void* UVMapper::creator()
{
	return new UVMapper();
}

bool UVMapper::isUndoable() const
{
	return true;
}


MStatus UVMapper::doIt( const MArgList& args )
//
//	Description:
//		implements the MEL UVMapper command.
//
//	Arguments:
//		args - the argument list that was passes to the command from MEL
//
//	Return Value:
//		MS::kSuccess - command succeeded
//		MS::kFailure - command failed (returning this value will cause the 
//                     MEL script that is being run to terminate unless the
//                     error is caught using a "catch" statement.
//
{
	_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
	MStatus stat = MS::kSuccess;
	MStatus selectionResult = MGlobal::getActiveSelectionList(currSel);

	// Typically, the doIt() method only collects the infomation required
	// to do/undo the action and then stores it in class members.  The 
	// redo method is then called to do the actuall work.  This prevents
	// code duplication.

	Options* opts = new Options;


	if(args.asString(0) == "Planar")
		opts->type = opts->PLANAR;
	else if(args.asString(0) == "Cylindrical")
		opts->type = opts->CYLINDRICAL;
	if(args.asString(0) == "ABF++")
		opts->type = opts->ABF;
	if(args.asString(1) == "Faces")
		opts->colType = opts->FACES;
	if(args.asString(1) == "Regions")
		opts->colType = opts->REGION;
	if( args.asString(2) != "" )	
		opts->radius = args.asString(2).asInt();
	if( args.asString(3) != "" )	
		opts->distortionAllowance = args.asString(3).asInt();
	else
		opts->distortionAllowance = 30;
	if( args.asString(4) == "Praxis" )
		opts->algoType = 0;
	if( args.asString(4) == "Nelder-Mead" )
		opts->algoType = 1;

	opts->time = args.asString(5).asInt();
	
	opts->distortionAllowance = opts->distortionAllowance / 100.0;
	
	opts->shareUV = 0;
	opts->mapName = "map1";

	//backup = new UvBackup(currSel, opts);
	MStatus result = redoIt(opts);
	_CrtDumpMemoryLeaks();
	return result;
}

MStatus UVMapper::redoIt(Options* opts)
//
//	Description:
//		implements redo for the MEL UVMapper command. 
//
//		This method is called when the user has undone a command of this type
//		and then redoes it.  No arguments are passed in as all of the necessary
//		information is cached by the doIt method.
//
//	Return Value:
//		MS::kSuccess - command succeeded
//		MS::kFailure - redoIt failed.  this is a serious problem that will
//                     likely cause the undo queue to be purged
//
{
	// Since this class is derived off of MPxCommand, you can use the 
	// inherited methods to return values and set error messages
	//
	
	//Project the current object
	if(opts->type == opts->ABF)
	{		
		MObject component;
		MDagPath node;		
	

		for(int i=0; i<currSel.length(); ++i)
		{
			currSel.getDagPath(i, node, component );
			MFnDependencyNode fn(node.node());
			std::cout << "\nOBJECT: " << fn.name().asChar() << std::endl;
		}

		currSel.getDependNode(0, component);
		currSel.getDagPath(0, node, component);
	
		MItMeshPolygon* faceIt = new MItMeshPolygon(node, component);		
		MItMeshVertex* vertIt = new MItMeshVertex(node, component);	
		MItMeshEdge* edgeIt = new MItMeshEdge(node, component);	
		MFnMesh* mesh = new MFnMesh(node);

		if(faceIt->count() == 0 || vertIt->count() == 0 || edgeIt->count() == 0 )
		{
			delete faceIt;
			delete vertIt;
			delete edgeIt;
			delete mesh;
			return MS::kSuccess;
		}

		Utilities::setIteratorPointers(vertIt, faceIt);
		cout << "Distortion Calculation" << endl;
		DistortionModel* dist = new DistortionModel(faceIt, vertIt, edgeIt, mesh);
		SeamCutter seamCutter(dist, opts->distortionAllowance, opts);
		delete faceIt;
		delete vertIt;
		delete edgeIt;
		delete mesh; 
		
		faceIt = new MItMeshPolygon(node, component);		
		vertIt = new MItMeshVertex(node, component);	
		edgeIt = new MItMeshEdge(node, component);	
		mesh = new MFnMesh(node);
		
		vector<int> seamVerts = seamCutter.getSeamVertices();
		vector<int> seamEdges = seamCutter.getSeamEdges();
		delete dist;

		AngleFlattener af(edgeIt, faceIt, vertIt, seamVerts, seamEdges);
		AngleSpace* as = af.flattenAngleSpace(opts->algoType, opts->time);
		AngleSpaceTransformer ast(as, faceIt, vertIt, opts, mesh);
		
		cout << "D: " << opts->distortionAllowance << endl;
		delete faceIt;
		delete vertIt;		
		delete opts;
	}
	else
	{
		ShapeProjection* projection = new ShapeProjection();
		projection->map(currSel, opts);
	}
	return MS::kSuccess;
}

MStatus UVMapper::undoIt()
//
//	Description:
//		implements undo for the MEL UVMapper command.  
//
//		This method is called to undo a previous command of this type.  The 
//		system should be returned to the exact state that it was it previous 
//		to this command being executed.  That includes the selection state.
//
//	Return Value:
//		MS::kSuccess - command succeeded
//		MS::kFailure - redoIt failed.  this is a serious problem that will
//                     likely cause the undo queue to be purged
//
{

	// You can also display information to the command window via MGlobal
	//
    backup->applyBackup();
	return MS::kSuccess;
}